package com.sakuraio.nextj.core.protocol;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.sakuraio.nextj.core.error.ErrorUtils;
import com.sakuraio.nextj.core.holder.SpringContextHolder;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;

/**
 * <p>Json响应协议</p>
 * <p>
 * nekoimi  2021/12/6 11:46
 */
@Slf4j
@Schema(description = "通用响应结构")
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class R<T> implements ErrorDetails, Serializable {
    public static final Integer CODE_OK = 0;
    public static final String CODE_OK_STR = "0";
    private static final String MESSAGE_OK = "ok";

    @Schema(description = "业务状态码；0 - 表示接口返回成功，其他值表示操作不成功，具体消息由msg字段给出")
    private Integer code;

    @Schema(description = "业务消息")
    private String msg;

    @Schema(description = "业务数据")
    @JsonAlias("result")
    private T data;

    @Schema(description = "异常信息")
    private String trace;

    @Schema(description = "请求ID")
    private String requestId;

    public static <T> Builder<T> ok() {
        return new Builder<>();
    }

    public static <T> Builder<T> ok(T data) {
        return new Builder<>(data);
    }

    public static <T> Builder<T> error(ErrorDetails errorDetails) {
        return new Builder<>(errorDetails);
    }

    public static <T> Builder<T> error(Integer code, String message) {
        return new Builder<>(code, message);
    }

    public static <T> Builder<T> error(Integer code, String message, Throwable t) {
        return new Builder<>(code, message, t);
    }

    @Override
    public Integer code() {
        return code;
    }

    @Override
    public String msg() {
        return msg;
    }

    @Override
    public String trace() {
        return trace;
    }

    @Getter
    public static class Builder<T> {
        private Integer code = CODE_OK;
        private String msg = MESSAGE_OK;
        private T data;
        private String trace;
        private Throwable t;
        private String requestId;

        public Builder() {
        }

        public Builder(T data) {
            this.data = data;
        }

        public Builder(ErrorDetails errorDetails) {
            this.code = errorDetails.code();
            this.msg = errorDetails.msg();
        }

        public Builder(Integer code, String message) {
            this.code = code;
            this.msg = message;
        }

        public Builder(Integer code, String message, Throwable t) {
            this.code = code;
            this.msg = message;
            this.t = t;
        }

        public Builder<T> code(Integer code) {
            this.code = code;
            return this;
        }

        public Builder<T> message(String message) {
            this.msg = message;
            return this;
        }

        public Builder<T> data(T data) {
            this.data = data;
            return this;
        }

        public Builder<T> trace(String trace) {
            this.trace = trace;
            return this;
        }

        public Builder<T> throwable(Throwable t) {
            this.t = t;
            return this;
        }

        public Builder<T> requestId(String requestId) {
            this.requestId = requestId;
            return this;
        }

        public R<T> build() {
            if (this.t != null && SpringContextHolder.isDebug()) {
                this.trace = ErrorUtils.trace(this.t);
            }
            return new R<>(this.code, this.msg, this.data, this.trace, this.requestId);
        }
    }
}
